package com.oj.core.impl;


import com.oj.api.core.CoreApi;
import com.oj.api.core.domain.JudgeInfo;
import com.oj.api.core.domain.ProblemInfo;
import com.oj.api.core.domain.ProblemSetCategoryInfo;
import com.oj.api.core.domain.ProblemSetInfo;
import com.oj.api.core.service.IProblemSetCategoryService;
import com.oj.common.InfoPage;
import com.oj.common.SystemTool;
import com.oj.common.constants.OperTypeEnum;
import com.oj.common.exception.BreezeeException;
import com.oj.core.entity.JudgeEntity;
import com.oj.core.entity.ProblemEntity;
import com.oj.core.entity.ProblemSetCategoryEntity;
import com.oj.core.entity.ProblemSetEntity;
import com.vladsch.flexmark.Extension;
import com.vladsch.flexmark.ast.Node;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.parser.ParserEmulationProfile;
import com.vladsch.flexmark.util.options.MutableDataSet;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.text.DecimalFormat;
import java.util.*;

/**
 * 题库服务
 * Created by Bing on 2018/5/4.
 */
@Service(CoreApi.BEAN_PROBLEM_SET_CATEGORY_SERVICE)
public class ProblemSetCategoryServiceImpl implements IProblemSetCategoryService{

    @Override
    public ProblemSetCategoryInfo saveInfo(ProblemSetCategoryInfo problemSetCategoryInfo) throws BreezeeException {

        if(problemSetCategoryInfo.getProperties().get("save")!=null){
            ProblemSetCategoryEntity entity = new ProblemSetCategoryEntity().buildCode(problemSetCategoryInfo.getCode()).findEntity();
            if(entity==null){
                problemSetCategoryInfo.setOperType(OperTypeEnum.WRITE);
                entity = new ProblemSetCategoryEntity().createWithInfo(problemSetCategoryInfo);
                entity.save();
            }
        }
        return null;
    }

    @Override
    public ProblemSetCategoryInfo findInfoById(String id) throws BreezeeException {


        return null;
    }

    @Override
    public List<ProblemSetCategoryInfo> listInfos(ProblemSetCategoryInfo problemSetCategoryInfo) {
        return new ProblemSetCategoryEntity().createWithInfo(problemSetCategoryInfo).list();
    }

    @Override
    public InfoPage<ProblemSetCategoryInfo> pageInfos(ProblemSetCategoryInfo problemSetCategoryInfo) {
        return new ProblemSetCategoryEntity().createWithInfo(problemSetCategoryInfo).page();
    }

    @Override
    public void deleteInfo(String id) throws BreezeeException {

    }

    @Override
    public ProblemInfo saveProblemInfo(ProblemInfo problemInfo) {

        if(problemInfo.getDescribe()!=null){

            String content = problemInfo.getDescribe();

            // markdown to image
            MutableDataSet options = new MutableDataSet();
            options.setFrom(ParserEmulationProfile.MARKDOWN);
            options.set(Parser.EXTENSIONS, Arrays.asList(new Extension[] { TablesExtension.create()}));
            Parser parser = Parser.builder(options).build();
            HtmlRenderer renderer = HtmlRenderer.builder(options).build();

            Node document = parser.parse(content);
            String html = renderer.render(document);

            html = html.replaceAll("<h1","<h1 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h2","<h2 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h3","<h3 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h4","<h4 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h5","<h5 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h6","<h6 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h7","<h7 style=\"font-weight: bold;\" ");
            html = html.replaceAll("<h8","<h8 style=\"font-weight: bold;\" ");

            problemInfo.setDescribeHtml(html);
        }

        if(problemInfo.getProperties().get("save")!=null){
            problemInfo.setOperType(OperTypeEnum.WRITE);
            problemInfo.setCode(SystemTool.getCode());
            ProblemEntity entity = new ProblemEntity().createWithInfo(problemInfo);
            return entity.save();
        }
        if(problemInfo.getProperties().get("update")!=null){
            ProblemEntity oldEntity = new ProblemEntity().buildCode(problemInfo.getCode()).findEntity();
            if(oldEntity!=null){

                oldEntity.setName(problemInfo.getName());
                oldEntity.setUpdator(problemInfo.getCreator());
                oldEntity.setUpdateTime(new Date());
                oldEntity.setDegree(problemInfo.getDegree());
                oldEntity.setAuthor(problemInfo.getAuthor());
                oldEntity.setCompany(problemInfo.getCompany());
                oldEntity.setScore(problemInfo.getScore());
                oldEntity.setDescribe(problemInfo.getDescribe());
                oldEntity.setDescribeHtml(problemInfo.getDescribeHtml());
                oldEntity.setLimitTime(problemInfo.getLimitTime());
                oldEntity.setLimitMoney(problemInfo.getLimitMoney());
                oldEntity.setTestDataCode(problemInfo.getTestDataCode());
                return oldEntity.save();
            }
        }
        return null;
    }

    @Override
    public InfoPage<ProblemInfo> findPageProblemInfos(ProblemInfo problemInfo) {
        return new ProblemEntity().createWithInfo(problemInfo).page();
    }


    @Override
    public ProblemSetInfo findProblemSetInfo(ProblemSetInfo problemSetInfo) {
        ProblemSetEntity entity =  new ProblemSetEntity().buildCode(problemSetInfo.getCode()).findEntity();
        //计算每个问题的提交数
        Set<ProblemEntity> set = entity.getProblems();
        for(ProblemEntity pe:set){
            //计算每个问题的提交数
           JudgeInfo judgeInfo = new JudgeInfo();
           judgeInfo.addProperties("problemCode",pe.getCode());
           judgeInfo.addProperties("problemSetCode",entity.getCode());
           int commitNumber = new JudgeEntity().createWithInfo(judgeInfo).list().size();
           pe.addProperties("commitNumber",commitNumber);
           //计算通过数
            judgeInfo.addProperties("status",50);
            int passNumber = new JudgeEntity().createWithInfo(judgeInfo).list().size();
            pe.addProperties("passNumber",passNumber);
            //计算通过率
            double passRate = 0;
            if(commitNumber!=0){
                passRate = (double)passNumber/commitNumber;
            }
            System.out.println(passRate);
            pe.addProperties("passRate",String.format("%.2f", passRate));
        }
        if(entity!=null){
            return entity.buildInfo(new ProblemSetInfo());
        }
         return null;
    }

    @Override
    public List<ProblemSetInfo> findProblemSetInfos(ProblemSetInfo problemSetInfo) {
        return new ProblemSetEntity().createWithInfo(problemSetInfo).list();
    }

    @Override
    public ProblemSetInfo addProblemsToSet(ProblemSetInfo problemSetInfo) {
        ProblemSetEntity entity = new ProblemSetEntity().buildCode(problemSetInfo.getCode()).findEntity();
        if(entity!=null){
            Set<String> problemCodes = new HashSet<>();
            entity.getProblems().forEach(a->{
                problemCodes.add(a.getCode());
            });
            problemSetInfo.getProblems().forEach(a->{
                if(!problemCodes.contains(a.getCode())){
                    ProblemEntity problemEntity = new ProblemEntity().buildCode(a.getCode()).findEntity();
                    if(problemEntity!=null){
                        entity.addProblem(problemEntity);
                    }
                }
            });
            return entity.save();
        }
        return null;
    }

    @Override
    public ProblemSetCategoryInfo createSet(ProblemSetCategoryInfo problemSetCategoryInfo) {
        ProblemSetCategoryEntity entity = new ProblemSetCategoryEntity().buildCode(problemSetCategoryInfo.getCode()).findEntity();
        if(entity!=null){
            Set<String> problemSetCodes = new HashSet<>();
            entity.getProblemSets().forEach(a->{
                problemSetCodes.add(a.getCode());
            });
            problemSetCategoryInfo.getProblemSets().forEach(a->{
                if(!problemSetCodes.contains(a.getCode())){
                    a.setOperType(OperTypeEnum.WRITE);
                    a.setCode(SystemTool.getCode());
                    ProblemSetEntity problemSetEntity = new ProblemSetEntity().createWithInfo(a);
                    entity.addProblemSet(problemSetEntity);
                }
            });
            return entity.save();
        }
        return null;
    }

    @Override
    public ProblemSetInfo updateSet(ProblemSetInfo problemSetInfo) {
        ProblemSetEntity entity = new ProblemSetEntity().buildCode(problemSetInfo.getCode()).findEntity();
        if (problemSetInfo.getProperties().get("update")!=null){
            if(entity==null){
                return null;
            }
            entity.setName(problemSetInfo.getName());
            entity.setType(problemSetInfo.getType());
            entity.setTimeType(problemSetInfo.getTimeType());
            entity.setStartTime(problemSetInfo.getStartTime());
            entity.setEndTime(problemSetInfo.getEndTime());
            entity.setOriginCode(problemSetInfo.getOriginCode());
            entity.setNotice(problemSetInfo.getNotice());
            entity.setCreator(problemSetInfo.getCreator());
            entity.setOpen(problemSetInfo.getOpen());
            entity.save();
            return entity.buildInfo();
        }
        return null;
    }

    @Override
    public ProblemSetInfo getProblemSet(@PathVariable("code") String code) {
        ProblemSetEntity entity = new ProblemSetEntity().buildCode(code).findEntity();
        if (entity!=null){
            return entity.buildInfo();
        }
        return null;
    }

    @Override
    public ProblemInfo findProblemInfo(String code) {
        ProblemEntity problemEntity = new ProblemEntity().buildCode(code).findEntity();
        if(problemEntity!=null){
            return problemEntity.buildInfo(new ProblemInfo());
        }
        return null;
    }




}
